{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Packing as many rectangles as possible into a larger rectangle with rotation\n",
    "\n",
    "This is a classic problem in computational geometry.\n",
    "Given a list of rectangles and a larger rectangle.\n",
    "The goal is to pack as many rectangles as possible into the larger rectangle.\n",
    "The rectangles can be rotated by 90 degrees.\n",
    "\n",
    "CP-SAT allows to easily model this problem using the `add_no_overlap_2D` constraint with `optional_interval_var`-variables.\n",
    "The `optional_interval_var`-variables allow to change the width and height of the rectangles based on some variables, which can be used to rotate the rectangles."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "container=Container(width=100, height=50) rectangles=[Rectangle(width=18, height=9, value=1), Rectangle(width=18, height=19, value=1), Rectangle(width=10, height=8, value=1), Rectangle(width=19, height=11, value=1), Rectangle(width=17, height=20, value=1), Rectangle(width=3, height=19, value=1), Rectangle(width=15, height=13, value=1), Rectangle(width=8, height=6, value=1), Rectangle(width=6, height=15, value=1), Rectangle(width=11, height=18, value=1), Rectangle(width=18, height=16, value=1), Rectangle(width=3, height=6, value=1), Rectangle(width=10, height=16, value=1), Rectangle(width=16, height=7, value=1), Rectangle(width=10, height=15, value=1), Rectangle(width=13, height=20, value=1), Rectangle(width=7, height=11, value=1), Rectangle(width=17, height=15, value=1), Rectangle(width=20, height=17, value=1), Rectangle(width=15, height=4, value=1), Rectangle(width=17, height=14, value=1), Rectangle(width=4, height=20, value=1), Rectangle(width=18, height=16, value=1), Rectangle(width=20, height=9, value=1), Rectangle(width=19, height=19, value=1), Rectangle(width=12, height=18, value=1), Rectangle(width=19, height=10, value=1), Rectangle(width=3, height=4, value=1), Rectangle(width=17, height=18, value=1), Rectangle(width=13, height=19, value=1), Rectangle(width=15, height=3, value=1), Rectangle(width=16, height=17, value=1), Rectangle(width=9, height=16, value=1), Rectangle(width=13, height=16, value=1), Rectangle(width=16, height=20, value=1), Rectangle(width=12, height=4, value=1), Rectangle(width=9, height=9, value=1), Rectangle(width=17, height=10, value=1), Rectangle(width=10, height=7, value=1), Rectangle(width=4, height=9, value=1), Rectangle(width=19, height=19, value=1), Rectangle(width=9, height=16, value=1), Rectangle(width=14, height=13, value=1), Rectangle(width=10, height=7, value=1), Rectangle(width=14, height=13, value=1), Rectangle(width=9, height=14, value=1), Rectangle(width=9, height=9, value=1), Rectangle(width=12, height=10, value=1), Rectangle(width=4, height=14, value=1), Rectangle(width=19, height=6, value=1)]\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "from solver import Instance\n",
    "\n",
    "with open(Path(\"./instances/instance_random_1.json\"), \"r\") as file:\n",
    "    instance = Instance.model_validate_json(file.read())\n",
    "print(instance)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from solver import RectangleKnapsackWithRotationsModel\n",
    "\n",
    "model = RectangleKnapsackWithRotationsModel(instance)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Starting CP-SAT solver v9.10.4067\n",
      "Parameters: max_time_in_seconds: 60 log_search_progress: true relative_gap_limit: 0.01\n",
      "Setting number of workers to 8\n",
      "\n",
      "Initial optimization model '': (model_fingerprint: 0x48bc7a9cdb3679d0)\n",
      "#Variables: 400 (#bools: 50 in objective)\n",
      "  - 100 Booleans in [0,1]\n",
      "  - 2 in [0,4]\n",
      "  - 2 in [0,6]\n",
      "  - 2 in [0,8]\n",
      "  - 6 in [0,9]\n",
      "  - 6 in [0,10]\n",
      "  - 2 in [0,11]\n",
      "  - 4 in [0,12]\n",
      "  - 8 in [0,14]\n",
      "  - 10 in [0,15]\n",
      "  - 10 in [0,16]\n",
      "  - 8 in [0,17]\n",
      "  - 12 in [0,18]\n",
      "  - 16 in [0,19]\n",
      "  - 12 in [0,20]\n",
      "  - 100 in [0,50]\n",
      "  - 100 in [0,100]\n",
      "#kInterval: 100 (#enforced: 100)\n",
      "#kLinear1: 8\n",
      "#kLinear2: 92\n",
      "#kNoOverlap2D: 1 (#rectangles: 50, #optional: 50, #quadratic_areas: 50)\n",
      "\n",
      "Starting presolve at 0.00s\n",
      "  2.93e-04s  0.00e+00d  [DetectDominanceRelations] \n",
      "  7.29e-03s  0.00e+00d  [PresolveToFixPoint] #num_loops=2 #num_dual_strengthening=1 \n",
      "  1.04e-03s  0.00e+00d  [ExtractEncodingFromLinear] \n",
      "[Symmetry] Graph for symmetry has 999 nodes and 1'370 arcs.\n",
      "[Symmetry] Symmetry computation done. time: 7.8e-05 dtime: 0.00016128\n",
      "  4.49e-03s  5.65e-05d  [Probe] #probed=224 \n",
      "  1.79e-04s  0.00e+00d  [MaxClique] \n",
      "  4.60e-05s  0.00e+00d  [DetectDominanceRelations] \n",
      "  2.06e-04s  0.00e+00d  [PresolveToFixPoint] #num_loops=1 #num_dual_strengthening=1 \n",
      "  2.42e-04s  0.00e+00d  [ProcessAtMostOneAndLinear] \n",
      "  2.62e-04s  0.00e+00d  [DetectDuplicateConstraints] \n",
      "  1.40e-05s  8.28e-07d  [DetectDominatedLinearConstraints] #relevant_constraints=92 \n",
      "  5.00e-06s  0.00e+00d  [DetectDifferentVariables] \n",
      "  2.00e-06s  0.00e+00d  [ProcessSetPPC] \n",
      "  1.88e-04s  0.00e+00d  [FindAlmostIdenticalLinearConstraints] \n",
      "  9.00e-06s  0.00e+00d  [FindBigAtMostOneAndLinearOverlap] \n",
      "  1.60e-05s  1.19e-05d  [FindBigVerticalLinearOverlap] \n",
      "  1.00e-06s  0.00e+00d  [FindBigHorizontalLinearOverlap] \n",
      "  1.00e-06s  0.00e+00d  [MergeClauses] \n",
      "  4.20e-05s  0.00e+00d  [DetectDominanceRelations] \n",
      "  1.79e-04s  0.00e+00d  [PresolveToFixPoint] #num_loops=1 #num_dual_strengthening=1 \n",
      "  3.80e-05s  0.00e+00d  [DetectDominanceRelations] \n",
      "  1.66e-04s  0.00e+00d  [PresolveToFixPoint] #num_loops=1 #num_dual_strengthening=1 \n",
      "[Symmetry] Graph for symmetry has 999 nodes and 1'370 arcs.\n",
      "[Symmetry] Symmetry computation done. time: 6.1e-05 dtime: 0.00016128\n",
      "  7.20e-04s  5.65e-05d  [Probe] #probed=224 \n",
      "  1.00e-06s  0.00e+00d  [MaxClique] \n",
      "  3.60e-05s  0.00e+00d  [DetectDominanceRelations] \n",
      "  1.68e-04s  0.00e+00d  [PresolveToFixPoint] #num_loops=1 #num_dual_strengthening=1 \n",
      "  4.10e-05s  0.00e+00d  [ProcessAtMostOneAndLinear] \n",
      "  7.80e-05s  0.00e+00d  [DetectDuplicateConstraints] \n",
      "  1.20e-05s  8.28e-07d  [DetectDominatedLinearConstraints] #relevant_constraints=92 \n",
      "  4.00e-06s  0.00e+00d  [DetectDifferentVariables] \n",
      "  2.00e-06s  0.00e+00d  [ProcessSetPPC] \n",
      "  1.00e-06s  0.00e+00d  [FindAlmostIdenticalLinearConstraints] \n",
      "  1.00e-05s  0.00e+00d  [FindBigAtMostOneAndLinearOverlap] \n",
      "  1.40e-05s  1.19e-05d  [FindBigVerticalLinearOverlap] \n",
      "  1.00e-06s  0.00e+00d  [FindBigHorizontalLinearOverlap] \n",
      "  1.00e-06s  0.00e+00d  [MergeClauses] \n",
      "  3.50e-05s  0.00e+00d  [DetectDominanceRelations] \n",
      "  1.61e-04s  0.00e+00d  [PresolveToFixPoint] #num_loops=1 #num_dual_strengthening=1 \n",
      "  7.00e-06s  0.00e+00d  [ExpandObjective] \n",
      "\n",
      "Presolve summary:\n",
      "  - 104 affine relations were detected.\n",
      "  - rule 'affine: new relation' was applied 104 times.\n",
      "  - rule 'deductions: 200 stored' was applied 1 time.\n",
      "  - rule 'linear: empty' was applied 8 times.\n",
      "  - rule 'linear: fixed or dup variables' was applied 24 times.\n",
      "  - rule 'linear: reduced variable domains' was applied 100 times.\n",
      "  - rule 'linear: remapped using affine relations' was applied 184 times.\n",
      "  - rule 'presolve: 12 unused variables removed.' was applied 1 time.\n",
      "  - rule 'presolve: iteration' was applied 2 times.\n",
      "  - rule 'variables: canonicalize domain' was applied 12 times.\n",
      "\n",
      "Presolved optimization model '': (model_fingerprint: 0x2f4fe3245544cb49)\n",
      "#Variables: 296 (#bools: 50 in objective)\n",
      "  - 96 Booleans in [0,1]\n",
      "  - 100 in [0,50]\n",
      "  - 100 in [0,100]\n",
      "#kInterval: 100 (#enforced: 100)\n",
      "#kLinear2: 8 (#enforced: 8)\n",
      "#kLinear3: 92 (#enforced: 92)\n",
      "#kNoOverlap2D: 1 (#rectangles: 50, #optional: 50, #quadratic_areas: 46)\n",
      "\n",
      "Preloading model.\n",
      "#Bound   0.03s best:-inf  next:[-0,50]    initial_domain\n",
      "[Symmetry] Graph for symmetry has 883 nodes and 1'370 arcs.\n",
      "[Symmetry] Symmetry computation done. time: 5.7e-05 dtime: 0.00015432\n",
      "#Model   0.03s var:296/296 constraints:201/201\n",
      "\n",
      "Starting search at 0.03s with 8 workers.\n",
      "6 full problem subsolvers: [core, default_lp, max_lp, no_lp, quick_restart, reduced_costs]\n",
      "1 first solution subsolver: [fj_short_default]\n",
      "13 incomplete subsolvers: [feasibility_pump, graph_arc_lns, graph_cst_lns, graph_dec_lns, graph_var_lns, packing_precedences_lns, packing_rectangles_lns, packing_slice_lns, rins/rens, rnd_cst_lns, rnd_var_lns, scheduling_precedences_lns, violation_ls]\n",
      "3 helper subsolvers: [neighborhood_helper, synchronization_agent, update_gap_integral]\n",
      "#1       0.03s best:-0    next:[1,50]     fj_short_default(batch:1 #lin_moves:0 #lin_evals:0 #weight_updates:0)\n",
      "#Bound   0.03s best:-0    next:[1,46]     quick_restart\n",
      "#Bound   0.04s best:-0    next:[1,39]     reduced_costs\n",
      "#2       0.04s best:1     next:[2,39]     violation_ls(batch:1 #solutions_imported:1 #lin_moves:0 #lin_evals:0 #gen_moves:3 #gen_evals:9 #comp_moves:3 #backtracks:0 #weight_updates:0)\n",
      "#3       0.04s best:4     next:[5,39]     rnd_var_lns (d=0.50 s=11 t=0.10 p=0.00 stall=0 h=auto_l0)\n",
      "#4       0.04s best:10    next:[11,39]    rnd_cst_lns (d=0.50 s=12 t=0.10 p=0.00 stall=0 h=auto_l0)\n",
      "#5       0.05s best:11    next:[12,39]    quick_restart (fixed_bools=0/648)\n",
      "#6       0.06s best:17    next:[18,39]    graph_arc_lns (d=0.50 s=14 t=0.10 p=0.00 stall=0 h=auto_l0)\n",
      "#7       0.06s best:18    next:[19,39]    quick_restart (fixed_bools=0/755)\n",
      "#8       0.06s best:19    next:[20,39]    graph_dec_lns (d=0.50 s=16 t=0.10 p=0.00 stall=0 h=auto_l0)\n",
      "#9       0.10s best:20    next:[21,39]    quick_restart (fixed_bools=0/1013)\n",
      "#10      0.12s best:21    next:[22,39]    quick_restart (fixed_bools=0/1048)\n",
      "#11      0.12s best:22    next:[23,39]    quick_restart (fixed_bools=0/1051)\n",
      "#12      0.13s best:23    next:[24,39]    quick_restart (fixed_bools=0/1056)\n",
      "#13      0.15s best:24    next:[25,39]    quick_restart (fixed_bools=0/1059)\n",
      "#14      0.17s best:25    next:[26,39]    quick_restart (fixed_bools=0/1111)\n",
      "#15      0.21s best:26    next:[27,39]    quick_restart (fixed_bools=0/1223)\n",
      "#16      0.27s best:27    next:[28,39]    quick_restart (fixed_bools=0/1351)\n",
      "#17      0.82s best:28    next:[29,39]    quick_restart (fixed_bools=0/2032)\n",
      "#18      2.15s best:32    next:[33,39]    packing_rectangles_lns (d=0.50 s=17 t=0.10 p=0.00 stall=0 h=auto_l0)\n",
      "#19      2.60s best:33    next:[34,39]    quick_restart (fixed_bools=0/3109)\n",
      "#20      6.46s best:35    next:[36,39]    rins_lp_lns (d=0.71 s=21 t=0.10 p=1.00 stall=1 h=auto_l0)\n",
      "#21     15.12s best:36    next:[37,39]    rnd_cst_lns (d=0.54 s=37 t=0.10 p=0.50 stall=1 h=auto_l0)\n",
      "#22     15.54s best:38    next:[39,39]    reduced_costs (fixed_bools=0/2083)\n",
      "#Model  15.63s var:295/296 constraints:201/201\n",
      "#Model  15.74s var:267/296 constraints:193/201 compo:259,1,1,1,1,1,1,1,1\n",
      "#Model  18.53s var:263/296 constraints:193/201 compo:259,1,1,1,1\n",
      "#Model  19.04s var:259/296 constraints:193/201\n",
      "\n",
      "Task timing                             n [     min,      max]      avg      dev     time         n [     min,      max]      avg      dev    dtime\n",
      "                        'core':         1 [   1.00m,    1.00m]    1.00m   0.00ns    1.00m         1 [  10.24s,   10.24s]   10.24s   0.00ns   10.24s\n",
      "                  'default_lp':         1 [   1.00m,    1.00m]    1.00m   0.00ns    1.00m         1 [  10.85s,   10.85s]   10.85s   0.00ns   10.85s\n",
      "            'feasibility_pump':        11 [ 10.00us,   6.90ms]   3.15ms   2.19ms  34.64ms         9 [ 62.58us, 423.44us] 263.05us 179.00us   2.37ms\n",
      "            'fj_short_default':         1 [  3.01ms,   3.01ms]   3.01ms   0.00ns   3.01ms         0 [  0.00ns,   0.00ns]   0.00ns   0.00ns   0.00ns\n",
      "               'graph_arc_lns':        11 [  7.84ms,    1.73s] 635.82ms 625.44ms    6.99s        11 [ 96.14us, 100.04ms]  47.39ms  48.20ms 521.28ms\n",
      "               'graph_cst_lns':        11 [  8.98ms,    1.44s] 580.57ms 564.26ms    6.39s        11 [ 46.32us, 102.30ms]  47.13ms  49.01ms 518.40ms\n",
      "               'graph_dec_lns':        11 [  6.46ms,    1.68s] 690.95ms 685.29ms    7.60s        11 [ 45.75us, 109.01ms]  47.81ms  49.49ms 525.91ms\n",
      "               'graph_var_lns':        11 [  3.16ms,    1.92s] 736.62ms 733.31ms    8.10s        11 [ 54.23us, 100.92ms]  47.50ms  48.48ms 522.55ms\n",
      "                      'max_lp':         1 [   1.00m,    1.00m]    1.00m   0.00ns    1.00m         1 [  16.02s,   16.02s]   16.02s   0.00ns   16.02s\n",
      "                       'no_lp':         1 [   1.00m,    1.00m]    1.00m   0.00ns    1.00m         1 [  10.40s,   10.40s]   10.40s   0.00ns   10.40s\n",
      "     'packing_precedences_lns':        10 [288.00us,    2.48s]    1.63s 603.26ms   16.29s         9 [ 83.62ms, 109.20ms]  98.32ms   7.09ms 884.90ms\n",
      "      'packing_rectangles_lns':        11 [857.01ms,    2.44s]    1.49s 530.34ms   16.40s        11 [ 20.58ms, 103.07ms]  63.34ms  35.07ms 696.70ms\n",
      "           'packing_slice_lns':        10 [342.76ms,    3.10s]    1.60s 863.08ms   16.00s        10 [  5.89ms, 106.63ms]  66.22ms  40.56ms 662.21ms\n",
      "               'quick_restart':         1 [   1.00m,    1.00m]    1.00m   0.00ns    1.00m         1 [  14.92s,   14.92s]   14.92s   0.00ns   14.92s\n",
      "               'reduced_costs':         1 [   1.00m,    1.00m]    1.00m   0.00ns    1.00m         1 [   5.98s,    5.98s]    5.98s   0.00ns    5.98s\n",
      "                   'rins/rens':        11 [  1.91ms,    1.69s] 982.97ms 621.45ms   10.81s        11 [ 10.00ns, 102.97ms]  71.94ms  44.24ms 791.36ms\n",
      "                 'rnd_cst_lns':        11 [  4.93ms,    1.90s] 865.02ms 718.76ms    9.52s        11 [125.62us, 100.46ms]  57.50ms  47.40ms 632.51ms\n",
      "                 'rnd_var_lns':        11 [  2.19ms,    1.47s] 676.34ms 609.74ms    7.44s        11 [ 33.13us, 110.62ms]  49.87ms  48.36ms 548.52ms\n",
      "  'scheduling_precedences_lns':        10 [428.00us,    2.61s]    1.20s 713.42ms   11.97s         8 [100.00ms, 103.63ms] 100.46ms   1.20ms 803.69ms\n",
      "                'violation_ls':        11 [  1.45ms, 299.02ms] 209.88ms  72.99ms    2.31s        11 [  1.35us,   1.74ms]   1.11ms 430.01us  12.26ms\n",
      "\n",
      "Search stats        Bools  Conflicts   Branches  Restarts  BoolPropag  IntegerPropag\n",
      "           'core':  2'480    276'863  2'296'453       193  52'313'390      9'608'688\n",
      "     'default_lp':  4'067    186'270  2'389'179    22'336  50'748'312      8'464'218\n",
      "         'max_lp':  3'731    156'024  1'605'288    33'287  26'836'206      8'688'544\n",
      "          'no_lp':  4'204    172'854  2'269'217    22'902  53'600'542      8'665'943\n",
      "  'quick_restart':  4'566    109'371  3'824'157    65'006  57'598'860     16'328'518\n",
      "  'reduced_costs':  2'395    161'739    197'792     1'936   7'055'230      2'938'476\n",
      "\n",
      "SAT stats           ClassicMinim  LitRemoved  LitLearned  LitForgotten  Subsumed  MClauses  MDecisions  MLitTrue  MSubsumed  MLitRemoved  MReused\n",
      "           'core':        69'136     430'257   6'272'406     5'855'386       630         0           0         0          0            0        0\n",
      "     'default_lp':        68'672     472'547   5'523'251     4'768'540       509     5'705     104'011         0        174        1'388    4'586\n",
      "         'max_lp':         6'984       8'638   2'049'693     1'816'736        41     4'167      28'252         0          3           11    2'036\n",
      "          'no_lp':        69'109     605'717   5'558'324     5'213'640       544     9'154     173'723         0        471        3'626    8'660\n",
      "  'quick_restart':        78'428     468'136   3'317'717     2'316'899       904    25'299     419'290         0      2'032       15'257   14'633\n",
      "  'reduced_costs':       149'769   1'930'873  11'060'234    10'257'892       153         0           0         0          0            0        0\n",
      "\n",
      "Lp stats            Component  Iterations  AddedCuts  OPTIMAL  DUAL_F.  DUAL_U.\n",
      "     'default_lp':          1      80'636         14   82'972        0      748\n",
      "         'max_lp':          1     414'363        648  602'164    5'733       54\n",
      "  'quick_restart':          1      62'881         14  120'404        0    1'596\n",
      "  'reduced_costs':          1      11'204        669  223'954      358        0\n",
      "\n",
      "Lp dimension                                                       Final dimension of first component\n",
      "     'default_lp':       0 rows, 50 columns, 0 entries with magnitude in [0.000000e+00, 0.000000e+00]\n",
      "         'max_lp':  104 rows, 296 columns, 329 entries with magnitude in [1.626921e-01, 1.000000e+00]\n",
      "  'quick_restart':     6 rows, 50 columns, 125 entries with magnitude in [5.000000e-01, 1.000000e+00]\n",
      "  'reduced_costs':   77 rows, 296 columns, 245 entries with magnitude in [1.811672e-01, 1.000000e+00]\n",
      "\n",
      "Lp debug            CutPropag  CutEqPropag   Adjust  Overflow  Bad  BadScaling\n",
      "     'default_lp':          0            0    3'186         0    3           0\n",
      "         'max_lp':         67            0  242'939         0  617           0\n",
      "  'quick_restart':          0            0    2'243         0    3           0\n",
      "  'reduced_costs':          0            0      754         0  645           0\n",
      "\n",
      "Lp pool             Constraints  Updates  Simplif  Merged  Shortened  Split  Strenghtened  Cuts/Call\n",
      "     'default_lp':           15        3       15       0         15      0             0      14/26\n",
      "         'max_lp':          849       77    1'007       0        619      0            32  648/8'844\n",
      "  'quick_restart':           15        0       45       0         45      0             0      14/22\n",
      "  'reduced_costs':          868       44      857       2        481      0            63  669/3'426\n",
      "\n",
      "Lp Cut                                 default_lp  max_lp  quick_restart  reduced_costs\n",
      "                               CG_FF:           1      96              1            144\n",
      "                                CG_K:           -      81              -            129\n",
      "                               CG_KL:           -       1              -              -\n",
      "                                CG_R:           4      44              4             68\n",
      "                               CG_RB:           -     116              -            109\n",
      "                              Clique:           -      60              -              3\n",
      "                                  IB:           -     143              -             83\n",
      "                            MIR_1_FF:           3      18              3             34\n",
      "                             MIR_1_K:           1       4              1              2\n",
      "                            MIR_1_KL:           -       1              -              -\n",
      "                             MIR_1_R:           3      46              3             57\n",
      "                            MIR_2_FF:           -       2              -              9\n",
      "          NoOverlap2dXCompletionTime:           -       5              -              1\n",
      "  NoOverlap2dXEnergy_optional_energy:           -       6              -             12\n",
      "                        ZERO_HALF_FF:           1      12              1              3\n",
      "                         ZERO_HALF_K:           -       4              -              -\n",
      "                         ZERO_HALF_R:           1       6              1              8\n",
      "                        ZERO_HALF_RB:           -       3              -              7\n",
      "\n",
      "LNS stats                        Improv/Calls  Closed  Difficulty  TimeLimit\n",
      "               'graph_arc_lns':          1/11     55%        0.64       0.10\n",
      "               'graph_cst_lns':          1/11     55%        0.69       0.10\n",
      "               'graph_dec_lns':          1/11     55%        0.69       0.10\n",
      "               'graph_var_lns':          1/11     55%        0.70       0.10\n",
      "     'packing_precedences_lns':           1/9     22%        0.07       0.10\n",
      "      'packing_rectangles_lns':          1/11     55%        0.48       0.10\n",
      "           'packing_slice_lns':          1/10     50%        0.34       0.10\n",
      "                   'rins/rens':          1/11     45%        0.38       0.10\n",
      "                 'rnd_cst_lns':          2/11     45%        0.43       0.10\n",
      "                 'rnd_var_lns':          2/11     55%        0.70       0.10\n",
      "  'scheduling_precedences_lns':           0/8      0%        0.02       0.10\n",
      "\n",
      "LS stats               Batches  Restarts  LinMoves  GenMoves  CompoundMoves  WeightUpdates\n",
      "  'fj_short_default':        1         1         0         0              0              0\n",
      "      'violation_ls':       11         0       105     6'621             16            593\n",
      "\n",
      "Solutions (22)               Num     Rank\n",
      "        'fj_short_default':    1    [1,1]\n",
      "           'graph_arc_lns':    1    [6,6]\n",
      "           'graph_dec_lns':    1    [8,8]\n",
      "  'packing_rectangles_lns':    1  [18,18]\n",
      "           'quick_restart':   12   [5,19]\n",
      "           'reduced_costs':    1  [22,22]\n",
      "             'rins_lp_lns':    1  [20,20]\n",
      "             'rnd_cst_lns':    2   [4,21]\n",
      "             'rnd_var_lns':    1    [3,3]\n",
      "            'violation_ls':    1    [2,2]\n",
      "\n",
      "Objective bounds     Num\n",
      "  'initial_domain':    1\n",
      "   'quick_restart':    1\n",
      "   'reduced_costs':    1\n",
      "\n",
      "Solution repositories    Added  Queried  Ignored  Synchro\n",
      "  'feasible solutions':     71      253        0       69\n",
      "        'lp solutions':  8'952        5    3'025      647\n",
      "                'pump':     20        6\n",
      "\n",
      "Improving bounds shared    Num\n",
      "                'max_lp':  132\n",
      "         'reduced_costs':    5\n",
      "\n",
      "Clauses shared    Num\n",
      "       'max_lp':   54\n",
      "\n",
      "CpSolverResponse summary:\n",
      "status: FEASIBLE\n",
      "objective: 38\n",
      "best_bound: 39\n",
      "integers: 297\n",
      "booleans: 4067\n",
      "conflicts: 186270\n",
      "branches: 2389179\n",
      "propagations: 50748312\n",
      "integer_propagations: 8464218\n",
      "restarts: 22336\n",
      "lp_iterations: 80636\n",
      "walltime: 60.0305\n",
      "usertime: 60.0305\n",
      "deterministic_time: 75.5248\n",
      "gap_integral: 2.61323\n",
      "solution_fingerprint: 0x3972ca5cd2db8655\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Solve!\n",
    "model.solve(60.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "placements=[Placement(x=0, y=20, rotated=False), None, Placement(x=61, y=16, rotated=False), Placement(x=0, y=0, rotated=False), None, Placement(x=58, y=16, rotated=False), Placement(x=11, y=35, rotated=True), Placement(x=28, y=20, rotated=False), Placement(x=45, y=26, rotated=False), Placement(x=0, y=32, rotated=False), None, Placement(x=11, y=32, rotated=True), Placement(x=24, y=0, rotated=False), Placement(x=61, y=24, rotated=False), Placement(x=18, y=20, rotated=False), None, Placement(x=51, y=26, rotated=False), None, None, Placement(x=24, y=16, rotated=False), Placement(x=24, y=36, rotated=False), Placement(x=20, y=0, rotated=False), None, Placement(x=0, y=11, rotated=False), None, Placement(x=75, y=32, rotated=False), Placement(x=39, y=16, rotated=False), Placement(x=36, y=20, rotated=False), None, None, Placement(x=0, y=29, rotated=False), Placement(x=81, y=13, rotated=False), Placement(x=65, y=0, rotated=False), Placement(x=52, y=0, rotated=False), None, Placement(x=87, y=32, rotated=False), Placement(x=41, y=41, rotated=False), Placement(x=28, y=26, rotated=False), Placement(x=51, y=37, rotated=False), Placement(x=77, y=23, rotated=False), None, Placement(x=34, y=0, rotated=False), Placement(x=74, y=0, rotated=False), Placement(x=71, y=16, rotated=False), Placement(x=61, y=31, rotated=False), Placement(x=43, y=0, rotated=False), Placement(x=87, y=36, rotated=False), Placement(x=88, y=0, rotated=False), Placement(x=96, y=36, rotated=False), Placement(x=50, y=44, rotated=False)]\n"
     ]
    }
   ],
   "source": [
    "print(model.solution)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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4fWWSzL+4c/RP3F+jolW82R5rxRiou2DifYeK5UptF9Of28bY4qyftcDy3vvvadMJqPa2toR02tra/Wzn/3srOXb2tq0efPms6bPvfY2t0sDAABF9v7776uqqsr19boeWPLV2tqqlpaW3PP+/n7NmzdPhw8fLsoPjPzE43HNnTtXR44cUSQSKXc5UxrHwh4cC3twLOwxMDCg+vp6VVdXF2X9rgeWmTNnyufzqa+vb8T0vr4+1dXVnbV8KBRSKHT2qYaqqirefBaJRCIcD0twLOzBsbAHx8IeXm9xLkB2fa3BYFCNjY3q6OjITXMcRx0dHYrFYm5vDgAATAFFOSXU0tKitWvXasmSJbruuuv0wAMP6OTJk7rjjjuKsTkAADDJFSWwfO5zn9O7776ru+++W729vbr66qv15JNPntURdzShUEj33HPPqKeJUHocD3twLOzBsbAHx8IexT4WHlOs648AAABcwr2EAACA9QgsAADAegQWAABgPQILAACwnnWBpb29XZdeeqnC4bCWLl2qF154odwlTXptbW365Cc/qcrKSs2aNUu33nqrenp6RiwzPDys5uZm1dTUqKKiQqtXrz5rcEC4b8uWLfJ4PNq4cWNuGseidH75y1/qD//wD1VTU6Np06bpE5/4hF588cXcfGOM7r77bl1yySWaNm2ampqa9MYbb5Sx4skpk8norrvu0vz58zVt2jT9+q//uv76r/96xD1rOBbF89xzz+nmm2/W7Nmz5fF49Nhjj42YP5Z9/8EHH2jNmjWKRCKKRqNat26dTpw4kV8hxiI7d+40wWDQfP/73zf//d//bb74xS+aaDRq+vr6yl3apLZixQqzfft2c+jQIXPw4EHzu7/7u6a+vt6cOHEit8yXv/xlM3fuXNPR0WFefPFFs2zZMvOpT32qjFVPfi+88IK59NJLzaJFi8yGDRty0zkWpfHBBx+YefPmmc9//vNm37595uc//7l56qmnzJtvvplbZsuWLaaqqso89thj5uWXXza/93u/Z+bPn29OnTpVxsonn3vvvdfU1NSYJ554wrz99ttm165dpqKiwnznO9/JLcOxKJ5///d/N9/85jfNj370IyPJ7N69e8T8sez7z372s2bx4sWmq6vL/Od//qf5+Mc/bm6//fa86rAqsFx33XWmubk59zyTyZjZs2ebtra2MlY19Rw7dsxIMnv27DHGGNPf328CgYDZtWtXbpn/+Z//MZJMZ2dnucqc1AYHB82CBQvM008/bX7rt34rF1g4FqXz9a9/3Vx//fXnnO84jqmrqzPf/va3c9P6+/tNKBQy//zP/1yKEqeMm266yXzhC18YMW3VqlVmzZo1xhiORSn9amAZy75/7bXXjCSzf//+3DL/8R//YTwej/nlL3855m1bc0oomUyqu7tbTU1NuWler1dNTU3q7OwsY2VTz8DAgCTlbmDV3d2tVCo14tg0NDSovr6eY1Mkzc3Nuummm0bsc4ljUUr/9m//piVLlugP/uAPNGvWLF1zzTV6+OGHc/Pffvtt9fb2jjgWVVVVWrp0KcfCZZ/61KfU0dGh119/XZL08ssva+/evVq5cqUkjkU5jWXfd3Z2KhqNasmSJbllmpqa5PV6tW/fvjFvq+x3az7tvffeUyaTOWs03NraWv3sZz8rU1VTj+M42rhxo5YvX66rrrpKktTb26tgMKhoNDpi2draWvX29pahyslt586deumll7R///6z5nEsSufnP/+5tm7dqpaWFv3FX/yF9u/frz/90z9VMBjU2rVrc/t7tM8sjoW7vvGNbygej6uhoUE+n0+ZTEb33nuv1qxZI0kcizIay77v7e3VrFmzRsz3+/2qrq7O6/hYE1hgh+bmZh06dEh79+4tdylT0pEjR7RhwwY9/fTTCofD5S5nSnMcR0uWLNHf/u3fSpKuueYaHTp0SN/97ne1du3aMlc3tfzwhz/Uo48+qh07dujKK6/UwYMHtXHjRs2ePZtjMYVYc0po5syZ8vl8Z13t0NfXp7q6ujJVNbWsX79eTzzxhH76059qzpw5uel1dXVKJpPq7+8fsTzHxn3d3d06duyYrr32Wvn9fvn9fu3Zs0cPPvig/H6/amtrORYlcskll+iKK64YMe3yyy/X4cOHJSm3v/nMKr4///M/1ze+8Q3ddttt+sQnPqE/+qM/0qZNm9TW1iaJY1FOY9n3dXV1Onbs2Ij56XRaH3zwQV7Hx5rAEgwG1djYqI6Ojtw0x3HU0dGhWCxWxsomP2OM1q9fr927d+uZZ57R/PnzR8xvbGxUIBAYcWx6enp0+PBhjo3LbrzxRr366qs6ePBg7rFkyRKtWbMm93+ORWksX778rMv7X3/9dc2bN0+SNH/+fNXV1Y04FvF4XPv27eNYuGxoaEhe78ivK5/PJ8dxJHEsymks+z4Wi6m/v1/d3d25ZZ555hk5jqOlS5eOfWMFdxl20c6dO00oFDKPPPKIee2118yXvvQlE41GTW9vb7lLm9S+8pWvmKqqKvPss8+ao0eP5h5DQ0O5Zb785S+b+vp688wzz5gXX3zRxGIxE4vFylj11HHmVULGcCxK5YUXXjB+v9/ce++95o033jCPPvqomT59uvmnf/qn3DJbtmwx0WjU/PjHPzavvPKKueWWW7iUtgjWrl1rfu3Xfi13WfOPfvQjM3PmTPO1r30ttwzHongGBwfNgQMHzIEDB4wkc99995kDBw6YX/ziF8aYse37z372s+aaa64x+/btM3v37jULFiyY2Jc1G2PM3//935v6+noTDAbNddddZ7q6uspd0qQnadTH9u3bc8ucOnXK/Mmf/ImZMWOGmT59uvn93/99c/To0fIVPYX8amDhWJTO448/bq666ioTCoVMQ0OD+Yd/+IcR8x3HMXfddZepra01oVDI3Hjjjaanp6dM1U5e8XjcbNiwwdTX15twOGw+9rGPmW9+85smkUjkluFYFM9Pf/rTUb8j1q5da4wZ275///33ze23324qKipMJBIxd9xxhxkcHMyrDo8xZwwVCAAAYCFr+rAAAACcC4EFAABYj8ACAACsR2ABAADWI7AAAADrEVgAAID1CCwAAMB6BBYAAGA9AgsAALAegQUAAFiPwAIAAKxHYAEAANb7f7Yv9flJiI3AAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from solver import plot_solution\n",
    "\n",
    "# plot the solution\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "if model.solution is not None:\n",
    "    fig, ax = plt.subplots(1)\n",
    "    plot_solution(ax, instance, model.solution)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mo312",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
